#include "modbus_rtu_master.h"
#include "ui_modbus_rtu_master.h"
#include <QModbusDataUnit>
#include <QSerialPortInfo>
#include <QLoggingCategory>
#include <QDebug>
#include <QMessageBox>

modbus_rtu_master::modbus_rtu_master(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::modbus_rtu_master)
{
    ui->setupUi(this);

    // 初始化UI
    ui->functionCodeCombo->addItem("Read Coils (0x01)", QModbusDataUnit::Coils);
    ui->functionCodeCombo->addItem("Read Discrete Inputs (0x02)", QModbusDataUnit::DiscreteInputs);
    ui->functionCodeCombo->addItem("Read Holding Registers (0x03)", QModbusDataUnit::HoldingRegisters);
    ui->functionCodeCombo->addItem("Read Input Registers (0x04)", QModbusDataUnit::InputRegisters);
    ui->functionCodeCombo->adjustSize();

    ui->serverAddressSpin->setRange(1, 247);            //设置服务器地址范围
    ui->startAddressSpin->setRange(0, 65535);           //设置寄存器起始地址
    ui->lengthSpin->setRange(1, 125);                   //设置寄存器长度

    //设置主窗体布局
    centralWidget()->setLayout(ui->verticalLayout);
    updateUiState(false);

    if (!modbusDevice) {
        setupModbusMaster();
    }
}

modbus_rtu_master::~modbus_rtu_master()
{
    if (modbusDevice)
        modbusDevice->disconnectDevice();
    delete ui;
}

void modbus_rtu_master::on_connectButton_clicked()
{
    if (modbusDevice->state() != QModbusDevice::ConnectedState) {
        modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, ui->portCombo->currentText());
        modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
        modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, ui->baudCombo->currentText().toInt());
        modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, 8);
        modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, 1);

        if (!modbusDevice->connectDevice()) {
            QMessageBox::critical(this, tr("Error"), tr("Connect failed: ") + modbusDevice->errorString());
        } else {
            updateUiState(true);
        }
    } else {
        modbusDevice->disconnectDevice();
        updateUiState(false);
    }
}

void modbus_rtu_master::on_sendButton_clicked()
{
    if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState)
        return;

    int serverAddress = ui->serverAddressSpin->value();
    int startAddress = ui->startAddressSpin->value();
    int length = ui->lengthSpin->value();
    QModbusDataUnit::RegisterType type = static_cast<QModbusDataUnit::RegisterType>(
        ui->functionCodeCombo->currentData().toInt());

    QModbusDataUnit dataUnit(type, startAddress, length);

    if (auto *reply = modbusDevice->sendReadRequest(dataUnit, serverAddress)) {
        if (!reply->isFinished()) {
            connect(reply, &QModbusReply::finished, this, &modbus_rtu_master::onReadReady);
        } else {
            delete reply; // 立即删除
        }
    } else {
        QMessageBox::critical(this, tr("Error"), tr("Send failed: ") + modbusDevice->errorString());
    }
}

void modbus_rtu_master::onReadReady()
{
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
        return;

    if (reply->error() == QModbusDevice::NoError) {
        const QModbusDataUnit unit = reply->result();
        QString result;

        for (uint i = 0; i < unit.valueCount(); i++) {
            if (unit.registerType() <= QModbusDataUnit::DiscreteInputs) {
                result += QString("Address: %1, Value: %2\n")
                    .arg(unit.startAddress() + i)
                    .arg(unit.value(i) ? "ON" : "OFF");
            } else {
                result += QString("Address: %1, Value: %2\n")
                    .arg(unit.startAddress() + i)
                    .arg(unit.value(i));
            }
        }

        ui->responseEdit->setPlainText(result);
    } else if (reply->error() == QModbusDevice::ProtocolError) {
        QString error = tr("Protocol error: %1 (Mobus exception: 0x%2)")
            .arg(reply->errorString())
            .arg(reply->rawResult().exceptionCode(), -1, 16);
        ui->responseEdit->setPlainText(error);
    } else {
        QString error = tr("Read response error: %1 (code: 0x%2)")
            .arg(reply->errorString())
            .arg(reply->error(), -1, 16);
        ui->responseEdit->setPlainText(error);
    }

    reply->deleteLater();
}

void modbus_rtu_master::handleError(QModbusDevice::Error error)
{
    if (error == QModbusDevice::NoError)
        return;

    QMessageBox::warning(this, tr("Device Error"), modbusDevice->errorString());
}

void modbus_rtu_master::setupModbusMaster()
{
    modbusDevice = new QModbusRtuSerialMaster(this);
    connect(modbusDevice, &QModbusClient::errorOccurred, this, &modbus_rtu_master::handleError);

    //设置帧间延迟，主从通讯时从站反馈速度过快导致主站异常
    modbusDevice->setInterFrameDelay(10);

    // 填充可用的串口
    ui->portCombo->clear();
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        ui->portCombo->addItem(info.portName());
    }

    // 设置默认波特率
    ui->baudCombo->addItems({"9600", "19200", "38400", "57600", "115200"});
    ui->baudCombo->setCurrentText("9600");
}

void modbus_rtu_master::updateUiState(bool connected)
{
    ui->connectButton->setText(connected ? tr("Disconnect") : tr("Connect"));
    ui->sendButton->setEnabled(connected);
    ui->portCombo->setEnabled(!connected);
    ui->baudCombo->setEnabled(!connected);
}
